
package com.chuanke.ckfamily.action.common;

import java.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.chuanke.ckfamily.action.base.Response;
import com.chuanke.ckfamily.action.common.model.Header;
import com.chuanke.ckfamily.dao.user.model.User;
import com.chuanke.ckfamily.service.base.FailCode;
import com.chuanke.ckfamily.service.common.CacheService;
import com.chuanke.ckfamily.service.common.TokenService;
import com.chuanke.ckfamily.service.common.model.UserToken;
import com.chuanke.ckfamily.service.exception.CFException;
import com.chuanke.ckfamily.service.user.UserService;
import com.clusterswisdom.kid.server.libary.util.SecurityUtil;

/**
 * Created by wangbin on 2017/6/26.
 */
public class ApiCheckerFilter implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(ApiCheckerFilter.class);

    public static final String HEAD_TOKEN = "token";

    public static final String HEAD_SIGN = "sign";

    public static final String HEAD_IMEI = "imei";

    public static final String HEAD_OS = "os";

    public static final String HEAD_VERSION = "version";

    public static final String SIGN_SALT = "NJ&chuanke*family_2017";

    private static Random random = new Random(System.currentTimeMillis());

    @Autowired
    private CacheService<String, Object> cacheService;

    @Autowired
    private UserService userService;

    @Autowired
    private TokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
        //不需要sign 请求
    	String requestURI = request.getRequestURI();
    	String contextPath = request.getContextPath();

    	if (StringUtils.isNotEmpty(contextPath)) {
    	    requestURI = requestURI.replaceAll(contextPath, "");
        }

        log.debug("perHandler =======> requestURI={}, imei={}", requestURI, request.getHeader(ApiCheckerFilter.HEAD_IMEI));
    	if (requestURI.equals("/api/interface/info")) {
    	    return true;
        }
        // 将face请求放过
        if(requestURI.startsWith("/api/face") ||
        	requestURI.equals("/api/comm/get") ||
                requestURI.startsWith("/api/task") ||
            requestURI.equals("/api/token/publicKey")) {
            return true;
        }

        String sign = request.getHeader(HEAD_SIGN);
        String requestSign = getSign(request);
        if (!requestSign.equals(sign)) {
        	log.debug("ApiCheckerFilter sign is not requestURI = {}, id={}, requestSign={}, sign={}", requestURI, request.getParameter("uid"), request.getParameter("uid"), requestSign,sign);
            sendResponse(FailCode.INVALITOKEN, response);
            return false;
        }

        //不需要token 请求
        if (requestURI.equals("/api/token/publicKey")
                || requestURI.equals("/api/token/refresh")
                || requestURI.equals("/api/user/alogin")
                || requestURI.equals("/api/user/login_token")) {
            return true;
        }

        String token = request.getHeader(HEAD_TOKEN);
        if (StringUtils.isEmpty(token)) {
        	Header header = getHeader(request);
        	log.info("ApiCheckerFilter token is null, requestURI= {}, id={}, header={}, ip={}", requestURI, request.getParameter("uid"), header, request.getLocalAddr());
            sendResponse(FailCode.RELOGIN, response);
            return false;
        }

        UserToken userToken = tokenService.getUserToken(token);
        if (!tokenInvalidate(request, userToken)) {
    		sendResponse(FailCode.INVALITOKEN, response);
            return false;
        }

        return true;
    }

    private boolean tokenInvalidate(HttpServletRequest request, UserToken userToken) {
        if (userToken == null) {
            Header header = getHeader(request);
            log.info("tokenInvalidate user token is null, requestURI= {}, id={}, header={}, ip={}",
                    request.getRequestURI(), request.getParameter("uid"), header, request.getLocalAddr());
            return false;
        }

        if (userToken.isInvalidate()) {
            return true;
        }

        User user = null;
        try {
            user = userService.findById(user.getId());
            if (userToken.getToken().equals(user.getToken())
                    || (userToken.getOldToken() != null
                    && userToken.getOldToken().equals(user.getToken()))
                    ) {
                return true;

            } else {
                Header header = getHeader(request);
                log.info("tokenInvalidate user token is isInvalidate, requestURI= {}, id={}, header={}, ip={}",
                        request.getRequestURI(), request.getParameter("uid"), header, request.getLocalAddr());
                return false;

            }

        } catch (CFException e) {
            Header header = getHeader(request);
            log.info("tokenInvalidate exception, requestURI= {}, id={}, header={}, ip={}",
                    request.getRequestURI(), request.getParameter("uid"), header, request.getLocalAddr());
            return false;

        }
    }

    private Header getHeader(HttpServletRequest request) {
    	Header header=new Header();
    	header.setToken(request.getHeader("token"));
		header.setSign(request.getHeader("sign"));
		header.setImei(request.getHeader("imei"));
		header.setOs(request.getHeader("os"));
		header.setVersion(request.getHeader("version"));
		return header;
	}

	private void sendResponse(FailCode failCode, HttpServletResponse response) {
        Response errorResponse = new Response(failCode, "您的账号极其宝贵，\n请重新登录传客！");
        String context = JSON.toJSONString(errorResponse);

        response.setCharacterEncoding("UTF-8");
        response.setStatus(200);
        try {
            log.debug("send fail response = {}", context);
            response.getWriter().print(context);

        }catch (Exception e) {
            e.printStackTrace();

        }
    }

    @NotNull
    private String getSign(HttpServletRequest request) {
        List<String> names = new ArrayList<String>(4);

        Enumeration<String> paramNameEnumeration = request.getParameterNames();
        while (paramNameEnumeration.hasMoreElements()) {
            String name = paramNameEnumeration.nextElement();
            String value = request.getParameter(name);
            if (!HEAD_SIGN.equals(name) || StringUtils.isNotEmpty(value)) {
                names.add(name);
            }
        }

        Collections.sort(names);

        String tags = "";
        StringBuilder contextBuilder = new StringBuilder(20);
        for (String param: names) {
            contextBuilder.append(tags);
            contextBuilder.append(param).append("=").append(request.getParameter(param));
            tags = "&";
        }

        contextBuilder.append(SIGN_SALT);
        log.debug("sign context = {}", contextBuilder.toString());
        return SecurityUtil.getMD5Str(contextBuilder.toString()).toLowerCase();
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { }
}